package com.tengju.bff.interfaces.covercharge.controller.portal;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.idanchuang.component.config.apollo.util.ConfigUtil;
import com.idanchuang.component.redis.util.DRedisLocks;
import com.tengju.bff.interfaces.app.withdraw.facade.DepositoryFacade;
import com.tengju.bff.interfaces.covercharge.constant.*;
import com.tengju.bff.interfaces.covercharge.entity.dto.IdName;
import com.tengju.bff.interfaces.covercharge.entity.dto.WithdrawalReason;
import com.tengju.bff.interfaces.covercharge.entity.po.ServiceSelfCertificationWithdraw;
import com.tengju.bff.interfaces.covercharge.entity.po.ServiceSign;
import com.tengju.bff.interfaces.covercharge.entity.vo.*;
import com.tengju.bff.interfaces.covercharge.service.*;
import com.tengju.bff.interfaces.covercharge.util.BeanMapperUtils;
import com.tengju.bff.interfaces.covercharge.util.UserUtils;
import com.tengju.bff.interfaces.shared.ApiResponse;
import com.tengju.bff.interfaces.shared.InterfaceCode;
import com.tengju.bff.interfaces.shared.InterfaceException;
import com.tengju.bff.interfaces.shared.StringConvertUtil;
import com.tengju.settlement.domain.model.depository.DepositoryChannel;
import com.tengju.user.domain.model.archive.letax.IdentityType;
import com.tengju.user.domain.shared.JsonUtil;
import com.tengju.settlement.domain.model.account.UserIdCode;
import com.tengju.settlement.domain.model.depository.DepositoryAccount;
import com.tengju.settlement.domain.model.depository.DepositoryAccountRepository;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Controller
@Slf4j
@RequestMapping("/api/withdrawal")
@Api(value = "withdrawal", tags = "服务费提现")
public class WithdrawalController {

    @Autowired
    private IServiceAccountTypeService serviceAccountTypeService;

    @Autowired
    private IServiceSignService serviceSignService;

    @Autowired
    private LeTaxOneService leTaxOneService;

    @Autowired
    private SelfCertificationService selfCertificationService;

    @Autowired
    private IServiceSelfCertificationWithdrawService serviceSelfCertificationWithdrawService;

    @Autowired
    private IRedisService redisService;
    @Autowired
    private DepositoryFacade depositoryFacade;
    @Autowired
    private DepositoryAccountRepository depositoryAccountRepository;


    @Value("${withdrawal.service.fee.apply.popup.blackList}")
    private String serviceFeeBlackListApplyPopupListString;

    @Value("${withdrawal.service.fee.apply.popup}")
    private String serviceFeeApplyPopupMapString;

    @Value("${depository.account.whiteList}")
    private String DepAccountWhiteList;


    @PostMapping("/applyBefore")
    @ResponseBody
    @ApiOperation(value = "个体提现申请前信息")
    public ApiResponse<WithdrawalApplyBeforeResult> applyBefore(HttpServletRequest request, @RequestBody WithdrawalApplyBeforeQuery applyBeforeQuery) {
        applyBeforeQuery.setFrom(UserUtils.getPlatFrom(request));
        Integer idCode = UserUtils.getIdCode(request);
        //账户类型
        CoverChargeEnum.ServiceAccountType accountType = CoverChargeEnum.ServiceAccountType.MANAGE_TYPE;
        WithdrawalApplyBeforeResult withdrawalApplyBeforeResult = leTaxOneService.queryWithdrawalApplyBefore(accountType, idCode);
        return ApiResponse.newSuccess(withdrawalApplyBeforeResult);
    }

    @PostMapping("/applyInfo")
    @ResponseBody
    @ApiOperation(value = "个体提现申请信息查询")
    public ApiResponse<WithdrawalApplyInfoResult> applyInfo(HttpServletRequest request, @RequestBody WithdrawalApplyInfoQuery withdrawalApplyInfoQuery) {
        withdrawalApplyInfoQuery.setFrom(UserUtils.getPlatFrom(request));
        Assert.notNull(withdrawalApplyInfoQuery.getMoney(), "申请金额不能为空");
        Assert.isTrue(withdrawalApplyInfoQuery.getMoney().compareTo(BigDecimal.ONE) >= 0, "提现金额1元起");
        Integer idCode = UserUtils.getIdCode(request);

        //账户类型
        CoverChargeEnum.ServiceAccountType accountType = CoverChargeEnum.ServiceAccountType.MANAGE_TYPE;
        WithdrawalApplyInfoResult withdrawalApplyInfo = leTaxOneService.queryWithdrawalApplyInfo(accountType, idCode, withdrawalApplyInfoQuery.getMoney());
        return ApiResponse.newSuccess(withdrawalApplyInfo);
    }

    @PostMapping("/apply")
    @ResponseBody
    @ApiOperation(value = "个体提现申请")
    public ApiResponse<?> apply(HttpServletRequest request, @RequestBody WithdrawalApply withdrawalApply) {
        log.info("个体提现申请...{}", JSON.toJSONString(withdrawalApply));

        //提现开关
        if (StringUtils.isNotBlank(redisService.queryWithdrawSwitchRedis())) {
            return ApiResponse.newFailure(CoverChargeErrorCode.BUSINESS_ERROR.getCode(), "系统升级中，预计24:00恢复使用");
        }

        Integer idCode = UserUtils.getIdCode(request);

        boolean hitWhiteList = false;
        if (!StringUtils.isEmpty(DepAccountWhiteList)) {
            List<UserIdCode> whiteIdCodeList = Arrays.stream(DepAccountWhiteList.split(","))
                    .map(Long::parseLong)
                    .map(UserIdCode::new)
                    .collect(Collectors.toList());
            hitWhiteList = whiteIdCodeList.contains(new UserIdCode(idCode));
        }

        //开户校验
        DepositoryAccount depositoryAccount;
        if (hitWhiteList) {
            depositoryAccount = depositoryAccountRepository
                    .getByIdCodeStatusNormal(new UserIdCode(idCode), DepositoryChannel.INTERNAL);
        } else {
            depositoryAccount = depositoryAccountRepository
                    .getByIdCodeStatusNormal(new UserIdCode(idCode), DepositoryChannel.PING_AN);
        }
        if (depositoryAccount == null) {
            throw new InterfaceException(InterfaceCode.DEP_ACCOUNT_NOT_OPEN);
        }


        withdrawalApply.setFrom(UserUtils.getPlatFrom(request));

        Assert.notNull(withdrawalApply.getMoney(), "请填写提现金额");
        Assert.isTrue(withdrawalApply.getMoney().compareTo(BigDecimal.ONE) >= 0, "提现金额1元起");

        //账户类型
        CoverChargeEnum.ServiceAccountType accountType = CoverChargeEnum.ServiceAccountType.MANAGE_TYPE;
        // DT 需要，ABM不需要理由
        if (CoverChargeEnum.ServiceAccountType.MANAGE_TYPE.equals(accountType)) {
            Assert.hasText(withdrawalApply.getReason(), "申请理由不能为空");
            List<WithdrawalReason> withdrawalReasonList = JSON.parseArray(withdrawalApply.getReason(), WithdrawalReason.class);

            //申请类型列表
            List<Integer> typeList = withdrawalReasonList.stream().map(WithdrawalReason::getType).collect(Collectors.toList());
            Assert.notEmpty(typeList, "申请理由类型有误");

            List<IdName> reasonConfigList = JSON.parseArray(ConfigUtil.getConfig().getString("apply.reason", ""), IdName.class);
            List<Integer> allTypeList = reasonConfigList.stream().map(IdName::getId).collect(Collectors.toList());
            Assert.isTrue(allTypeList.containsAll(typeList), "申请理由类型有误");
        }


        if (checkBlackListIsExistIdCode(idCode)) {
            return ApiResponse.newFailure(CoverChargeErrorCode.FORBIDDEN_ACCOUNT_WITHDRAW.getCode(),
                    CoverChargeErrorCode.FORBIDDEN_ACCOUNT_WITHDRAW.getMsg());
        }

        return DRedisLocks.runWithLock(BizConstants.WITHDRAWAL_APPLY + idCode, 500, () -> {
            try {
                return ApiResponse.newSuccess(leTaxOneService.withdrawalApply(accountType, idCode, withdrawalApply, depositoryAccount));
            } catch (Exception e) {
                log.error("withdrawalApply error", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), e.getMessage());
            }
        });

    }

    @PostMapping("/companyApply")
    @ResponseBody
    @ApiOperation(value = "自认证提现申请")
    public ApiResponse<?> companyApply(HttpServletRequest request, @RequestBody WithdrawalCompanyApply withdrawalCompanyApply) {
        log.info("自认证提现申请...{}", JSON.toJSONString(withdrawalCompanyApply));

        //提现开关
        if (StringUtils.isNotBlank(redisService.queryWithdrawSwitchRedis())) {
            return ApiResponse.newFailure(CoverChargeErrorCode.BUSINESS_ERROR.getCode(), "系统升级中，预计24:00恢复使用");
        }

        Integer idCode = UserUtils.getIdCode(request);

        boolean hitWhiteList = false;
        if (!StringUtils.isEmpty(DepAccountWhiteList)) {
            List<UserIdCode> whiteIdCodeList = Arrays.stream(DepAccountWhiteList.split(","))
                    .map(Long::parseLong)
                    .map(UserIdCode::new)
                    .collect(Collectors.toList());
            hitWhiteList = whiteIdCodeList.contains(new UserIdCode(idCode));
        }

        //开户校验
        DepositoryAccount depositoryAccount;
        if (hitWhiteList) {
            depositoryAccount = depositoryAccountRepository
                    .getByIdCodeStatusNormal(new UserIdCode(idCode), DepositoryChannel.INTERNAL);
        } else {
            depositoryAccount = depositoryAccountRepository
                    .getByIdCodeStatusNormal(new UserIdCode(idCode), DepositoryChannel.PING_AN);
        }
        if (depositoryAccount == null) {
            throw new InterfaceException(InterfaceCode.DEP_ACCOUNT_NOT_OPEN);
        }

        withdrawalCompanyApply.setFrom(UserUtils.getPlatFrom(request));

        Assert.notNull(withdrawalCompanyApply.getMoney(), "请填写提现金额");
        Assert.isTrue(withdrawalCompanyApply.getMoney().compareTo(BigDecimal.ONE) >= 0, "提现金额1元起");
        Assert.notNull(withdrawalCompanyApply.getInvoice(), "请选择发票类型");
        Assert.notNull(withdrawalCompanyApply.getInvoiceImg(), "请上传发票图片");

        //账户类型
        CoverChargeEnum.ServiceAccountType accountType = CoverChargeEnum.ServiceAccountType.MANAGE_TYPE;

        // DT 需要，ABM不需要理由
        if (CoverChargeEnum.ServiceAccountType.MANAGE_TYPE.equals(accountType)) {
            Assert.hasText(withdrawalCompanyApply.getReason_new(), "申请理由不能为空");
            List<WithdrawalReason> withdrawalReasonList = JSON.parseArray(withdrawalCompanyApply.getReason_new(), WithdrawalReason.class);
            //申请类型列表
            List<Integer> typeList = withdrawalReasonList.stream().map(WithdrawalReason::getType).collect(Collectors.toList());
            Assert.notEmpty(typeList, "申请理由类型有误");
            List<IdName> reasonConfigList = JSON.parseArray(ConfigUtil.getConfig().getString("apply.reason", ""), IdName.class);
            List<Integer> allTypeList = reasonConfigList.stream().map(IdName::getId).collect(Collectors.toList());

            Assert.isTrue(allTypeList.containsAll(typeList), "申请理由类型有误");
        }


        if (checkBlackListIsExistIdCode(idCode)) {
            return ApiResponse.newFailure(CoverChargeErrorCode.FORBIDDEN_ACCOUNT_WITHDRAW.getCode(),
                    CoverChargeErrorCode.FORBIDDEN_ACCOUNT_WITHDRAW.getMsg());
        }

        return DRedisLocks.runWithLock(BizConstants.WITHDRAWAL_APPLY_COMPANY + idCode, 500, () -> {
            try {
                return ApiResponse.newSuccess(selfCertificationService.withdrawalApply(accountType, idCode, withdrawalCompanyApply, depositoryAccount));
            } catch (Exception e) {
                log.error("company withdrawalApply error", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), e.getMessage());
            }
        });
    }

    @GetMapping("/companyApply/{id}")
    @ResponseBody
    @ApiOperation(value = "查询自认证提现申请信息")
    public ApiResponse<SelfCertificationWithdrawQuery> companyApplyInfo(HttpServletRequest request, @PathVariable("id") Long id) {
        Assert.notNull(id, "自认证提现申请id不能为空");
        ServiceSelfCertificationWithdraw certificationWithdraw = serviceSelfCertificationWithdrawService.getById(id);
        Assert.notNull(certificationWithdraw, "没有找到该条申请记录");
        Integer idCode = UserUtils.getIdCode(request);
        Assert.isTrue(idCode.equals(certificationWithdraw.getIdCode()), "用户不一致");
        SelfCertificationWithdrawQuery selfCertificationWithdrawQuery = BeanMapperUtils.map(certificationWithdraw, SelfCertificationWithdrawQuery.class);
        return ApiResponse.newSuccess(selfCertificationWithdrawQuery);
    }

    @PostMapping("/companyReapply")
    @ResponseBody
    @ApiOperation(value = "自认证提现重新申请")
    public ApiResponse<?> companyReapply(HttpServletRequest request, @RequestBody WithdrawalCompanyReApply withdrawalCompanyReApply) {
        //提现开关
        if (StringUtils.isNotBlank(redisService.queryWithdrawSwitchRedis())) {
            return ApiResponse.newFailure(CoverChargeErrorCode.BUSINESS_ERROR.getCode(), "系统升级中，预计24:00恢复使用");
        }
        log.info("自认证提现重新申请...{}", JSON.toJSONString(withdrawalCompanyReApply));

        Map<String, String> serviceFeeApplyPopupMap = JsonUtil.toMap(serviceFeeApplyPopupMapString);
        List<String> identityVal = Lists.newArrayList(StringUtils.split(serviceFeeApplyPopupMap.get("identity"), ","));
        if (identityVal.contains(IdentityType.CERTIFIED_BUSINESS.getVal()) ||
                identityVal.contains(IdentityType.CERTIFIED_INDIVIDUAL.getVal())) {
            String canApply = serviceFeeApplyPopupMap.get("canApply");
            if (!Boolean.parseBoolean(canApply)) {
                return ApiResponse.newFailure(CoverChargeErrorCode.BUSINESS_ERROR.getCode(), serviceFeeApplyPopupMap.get("desc"));
            }
        }

        Integer idCode = UserUtils.getIdCode(request);

        boolean hitWhiteList = false;
        if (!StringUtils.isEmpty(DepAccountWhiteList)) {
            List<UserIdCode> whiteIdCodeList = Arrays.stream(DepAccountWhiteList.split(","))
                    .map(Long::parseLong)
                    .map(UserIdCode::new)
                    .collect(Collectors.toList());
            hitWhiteList = whiteIdCodeList.contains(new UserIdCode(idCode));
        }

        //开户校验
        DepositoryAccount depositoryAccount;
        if (hitWhiteList) {
            depositoryAccount = depositoryAccountRepository
                    .getByIdCodeStatusNormal(new UserIdCode(idCode), DepositoryChannel.INTERNAL);
        } else {
            depositoryAccount = depositoryAccountRepository
                    .getByIdCodeStatusNormal(new UserIdCode(idCode), DepositoryChannel.PING_AN);
        }
        if (depositoryAccount == null) {
            throw new InterfaceException(InterfaceCode.DEP_ACCOUNT_NOT_OPEN);
        }


        Assert.notNull(withdrawalCompanyReApply.getId(), "自认证提现申请id不能为空");
        Assert.notNull(withdrawalCompanyReApply.getInvoice(), "请选择发票类型");
        Assert.notNull(withdrawalCompanyReApply.getInvoiceImg(), "请上传发票图片");

        if (StringUtils.isNotEmpty(withdrawalCompanyReApply.getReason_new())) {
            List<WithdrawalReason> withdrawalReasonList = JSON.parseArray(withdrawalCompanyReApply.getReason_new(), WithdrawalReason.class);
            //申请类型列表
            List<Integer> typeList = withdrawalReasonList.stream().map(WithdrawalReason::getType).collect(Collectors.toList());
            Assert.notEmpty(typeList, "申请理由类型有误");

            List<IdName> reasonConfigList = JSON.parseArray(ConfigUtil.getConfig().getString("apply.reason", ""), IdName.class);
            List<Integer> allTypeList = reasonConfigList.stream().map(IdName::getId).collect(Collectors.toList());
            Assert.isTrue(allTypeList.containsAll(typeList), "申请理由类型有误");
        }


        return DRedisLocks.runWithLock(BizConstants.WITHDRAWAL_REAPPLY_COMPANY + idCode, 500, () -> {
            try {
                return ApiResponse.newSuccess(selfCertificationService.withdrawalApplyUpdate(idCode, withdrawalCompanyReApply));
            } catch (Exception e) {
                log.error("company withdrawalReApply error", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), e.getMessage());
            }
        });
    }


    @PostMapping("/cancel")
    @ResponseBody
    @ApiOperation(value = "取消服务费提现申请")
    public ApiResponse<?> cancel(HttpServletRequest request, @RequestBody WithdrawalApplyCancel withdrawalCancel) {
        //提现开关
        if (StringUtils.isNotBlank(redisService.queryWithdrawSwitchRedis())) {
            return ApiResponse.newFailure(CoverChargeErrorCode.BUSINESS_ERROR.getCode(), "系统升级中，预计24:00恢复使用");
        }
        log.info("取消服务费提现申请...{}", JSON.toJSONString(withdrawalCancel));
        Assert.notNull(withdrawalCancel.getId(), "提现申请ID不能为空");
        withdrawalCancel.setFrom(UserUtils.getPlatFrom(request));

        //账户类型
        CoverChargeEnum.ServiceAccountType accountType = CoverChargeEnum.ServiceAccountType.MANAGE_TYPE;

        Integer idCode = UserUtils.getIdCode(request);

        ServiceSign serviceSignParam = new ServiceSign();
        serviceSignParam.setIdCode(idCode);
        serviceSignParam.setPlatformCode(accountType.getPlatform());
        ServiceSign serviceSign = serviceSignService.getOne(new QueryWrapper<>(serviceSignParam));
        Assert.isTrue(serviceSign != null && CoverChargeEnum.CommonStatus.YES.getName().equals(serviceSign.getIsSigned()), "未签约");

        return DRedisLocks.runWithLock(BizConstants.WITHDRAWAL_CANCEL + idCode, 500, () -> {
            try {
                if (SignIdentityEnum.person.toString().equals(serviceSign.getCurrentIdentity())
                        || SignIdentityEnum.regist_soho.toString().equals(serviceSign.getCurrentIdentity())) {
                    leTaxOneService.withdrawalApplyCancel(idCode, accountType.getPlatform(), withdrawalCancel.getId(), WithdrawalCancelEnum.self);
                } else if (SignIdentityEnum.certified_individual.toString().equals(serviceSign.getCurrentIdentity())
                        || SignIdentityEnum.certified_business.toString().equals(serviceSign.getCurrentIdentity())) {
                    selfCertificationService.withdrawalApplyCancel(idCode, accountType.getPlatform(), withdrawalCancel.getId());
                }
                return ApiResponse.newSuccess();
            } catch (Exception e) {
                log.error("cancelWithdrawalApply error", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), e.getMessage());
            }
        });
    }

    @PostMapping("/updateApplyReason")
    @ResponseBody
    @ApiOperation(value = "提现申请理由修改")
    public ApiResponse<?> updateApplyReason(HttpServletRequest request, @RequestBody WithdrawalApply withdrawalApply) {
        //提现开关
        if (StringUtils.isNotBlank(redisService.queryWithdrawSwitchRedis())) {
            return ApiResponse.newFailure(CoverChargeErrorCode.BUSINESS_ERROR.getCode(), "系统升级中，预计24:00恢复使用");
        }
        log.info("个体提现申请...{}", JSON.toJSONString(withdrawalApply));
        Assert.notNull(withdrawalApply.getId(), "提现记录ID不能为空");
        Assert.hasText(withdrawalApply.getReason(), "申请理由不能为空");
        withdrawalApply.setFrom(UserUtils.getPlatFrom(request));
        Integer idCode = UserUtils.getIdCode(request);
        Assert.notNull(idCode, "代理id不能为空");

        //账户类型
        CoverChargeEnum.ServiceAccountType accountType = CoverChargeEnum.ServiceAccountType.MANAGE_TYPE;
        ServiceSign serviceSignParam = new ServiceSign();
        serviceSignParam.setIdCode(idCode);
        serviceSignParam.setPlatformCode(accountType.getPlatform());
        ServiceSign serviceSign = serviceSignService.getOne(new QueryWrapper<>(serviceSignParam));
        Assert.isTrue(serviceSign != null && CoverChargeEnum.CommonStatus.YES.getName().equals(serviceSign.getIsSigned()), "未签约");

        List<WithdrawalReason> withdrawalReasonList = JSON.parseArray(withdrawalApply.getReason(), WithdrawalReason.class);
        //申请类型列表
        List<Integer> typeList = withdrawalReasonList.stream().map(WithdrawalReason::getType).collect(Collectors.toList());
        Assert.notEmpty(typeList, "申请理由类型有误");

        List<IdName> reasonConfigList = JSON.parseArray(ConfigUtil.getConfig().getString("apply.reason", ""), IdName.class);
        List<Integer> allTypeList = reasonConfigList.stream().map(IdName::getId).collect(Collectors.toList());
        Assert.isTrue(allTypeList.containsAll(typeList), "申请理由类型有误");

        return DRedisLocks.runWithLock(BizConstants.WITHDRAWAL_APPLY + idCode, 500, () -> {
            try {
                if (SignIdentityEnum.person.toString().equals(serviceSign.getCurrentIdentity())
                        || SignIdentityEnum.regist_soho.toString().equals(serviceSign.getCurrentIdentity())) {
                    leTaxOneService.updateApplyReason(idCode, accountType.getPlatform(), withdrawalApply);
                } else if (SignIdentityEnum.certified_individual.toString().equals(serviceSign.getCurrentIdentity())
                        || SignIdentityEnum.certified_business.toString().equals(serviceSign.getCurrentIdentity())) {
                    selfCertificationService.updateApplyReason(idCode, accountType.getPlatform(), withdrawalApply, serviceSign.getBeforeIdentity());
                }
                return ApiResponse.newSuccess();
            } catch (Exception e) {
                log.error("withdrawalApplyReasonUpdate error", e);
                return ApiResponse.newFailure(CoverChargeErrorCode.SYS_ERROR.getCode(), "申请理由修改失败");
            }
        });
    }


    private Boolean checkBlackListIsExistIdCode(Integer idCode) {
        List<Long> userIdCodeList = StringConvertUtil.stringConvertToLongList(serviceFeeBlackListApplyPopupListString);
        for (Long value : userIdCodeList) {
            if (idCode.longValue() == value) {
                return true;
            }
        }
        return false;
    }
}
